﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Windows.Forms;
using System.Xml;
using System.Xml.Linq;

namespace Sharper.Utils
{
    /// <summary>
    /// 操作XML文件的工具类
    /// </summary>
    public static class XMLUtil
    {
        #region 变量

        public static string xmlCfgPath = string.Empty; //配置文件的路径


        //根节点
        public const string RootNode = "RevitTool"; //XML文件的根节点名称

        //子节点
        public const string ProjectNameNode = "ProjectName"; //项目名称

        //子节点
        public const string RevitVersionNode = "RevitVersion"; //所有Revit的版本
        public const string VersionNode = "Version";

        //子节点
        public const string DebugPathNode = "DebugPath"; //不同Revit的版本的Debug路径
        public const string ReleasePathNode = "ReleasePath"; //不同Revit的版本的Release路径
        public const string CsprojPathNode = "CsprojPath"; //不同Revit的版本的Csproj路径
        public const string PathNode = "Path";

        //节点属性
        public const string NodeAttribute = "Version"; //节点属性名称

        #endregion

        #region 创建默认xml时所用的变量

        private const string _projName = "test";

        private const string _version1 = "2016";
        private const string _version2 = "2018";

        private const string _debug1 = "D:\\RevitTool\\bin\\Debug\\2016\\test.dll";
        private const string _debug2 = "D:\\RevitTool\\bin\\Debug\\2018\\test.dll";

        private const string _release1 = "D:\\RevitTool\\bin\\Release\\2016\\test.dll";
        private const string _release2 = "D:\\RevitTool\\bin\\Release\\2018\\test.dll";

        private const string _csproj1 = "D:\\RevitTool\\test2016.csproj";
        private const string _csproj2 = "D:\\RevitTool\\test2018.csproj";

        #endregion


        #region 公开的XML方法

        /// <summary> 
        /// 初始化XML
        /// </summary>
        /// <param name="strXmlPath"></param>
        public static bool EnsureXMLFile(string strXmlPath)
        {
            //检查是否存在XML配置文件
            if (CheckXMLFile(strXmlPath))
            {
                return true;
            }
            else
            {
                //创建新的XML文件
                if (MessageBox.Show("当前配置文件缺失,是否创建默认配置?", "Warning", MessageBoxButtons.YesNo) == DialogResult.Yes)
                {
                    CreateXMLFile(strXmlPath);
                    return true;
                }
                else
                {
                    return false;
                }
            }
        }

        /// <summary>
        /// 获取XML配置文件根节点下的指定节点
        /// </summary>
        /// <param name="XMLPath">XML的路径</param>
        /// <param name="elementName">标签名称</param>
        /// <returns></returns>
        public static XmlNode GetXmlNode(string XMLPath, string elementName)
        {
            try
            {
                //将XML文件加载进来
                XmlDocument xmlDoc = new XmlDocument();
                XmlReaderSettings settings = new XmlReaderSettings();
                settings.IgnoreComments = true; //忽略文档里面的注释
                XmlReader reader = XmlReader.Create(XMLPath, settings);
                xmlDoc.Load(reader);

                //获得根节点
                XmlNode rootNode = xmlDoc.SelectSingleNode(RootNode);
                XmlNode xmlNode = rootNode.SelectSingleNode(elementName);

                reader.Close();


                return xmlNode;
            }
            catch (Exception e)
            {
                return null;
            }
        }


        /// <summary>
        /// 获取Csproj工程文件根节点下的指定节点
        /// </summary>
        /// <param name="XMLPath">XML的路径</param>
        /// <returns></returns>
        public static List<XmlNode> GetCsprojNode(string XMLPath)
        {
            try
            {
                //将XML文件加载进来
                XmlDocument xmlDoc = new XmlDocument();
                XmlReaderSettings settings = new XmlReaderSettings();
                settings.IgnoreComments = true; //忽略文档里面的注释
                XmlReader reader = XmlReader.Create(XMLPath, settings);

                xmlDoc.Load(XMLPath);


                //获得根节点
                XmlNamespaceManager nsMgr = new XmlNamespaceManager(xmlDoc.NameTable); //这一步实例化一个xml命名空间管理器
                nsMgr.AddNamespace("ns", "http://schemas.microsoft.com/developer/msbuild/2003");

                //获得根节点
                XmlNode rootNode = xmlDoc.SelectSingleNode("/ns:Project", nsMgr);
                XmlNodeList xmlNodeList = rootNode.SelectNodes("/ns:Project/ns:ItemGroup", nsMgr);

                List<XmlNode> newList = new List<XmlNode>();
                for (int i = 1; i < xmlNodeList.Count; i++)
                {
                    newList.Add(xmlNodeList[i]);
                }

                reader.Close();

                return newList;
            }
            catch (Exception e)
            {
                return null;
            }
        }

        /// <summary>
        /// 插入Csproj工程文件根节点下的指定节点
        /// </summary>
        /// <param name="XMLPath">XML的路径</param>
        /// <returns></returns>
        public static void InsertCsprojNode(string XMLPath, List<XmlNode> itemList)
        {
            try
            {
                //将XML文件加载进来
                XmlDocument xmlDoc = new XmlDocument();
                XmlReaderSettings settings = new XmlReaderSettings();
                XmlReader reader = XmlReader.Create(XMLPath, settings);
                xmlDoc.Load(reader);

                XmlNamespaceManager nsMgr = new XmlNamespaceManager(xmlDoc.NameTable); //这一步实例化一个xml命名空间管理器
                nsMgr.AddNamespace("ns", "http://schemas.microsoft.com/developer/msbuild/2003");

                //获得根节点
                XmlNode rootNode = xmlDoc.SelectSingleNode("/ns:Project", nsMgr);
                XmlNodeList xmlNodeList = rootNode.SelectNodes("/ns:Project/ns:ItemGroup", nsMgr);

                for (int i = 1; i < xmlNodeList.Count; i++)
                {
                    rootNode.RemoveChild(xmlNodeList[i]);
                }

                XmlNode flagNode = xmlNodeList[0];

                List<XmlNode> creatList = new List<XmlNode>();
                foreach (XmlNode xmlNode in itemList)
                {
                    //创建ItemGroup节点
                    XmlNode nodeA = xmlDoc.CreateElement("ItemGroup", xmlDoc.DocumentElement.NamespaceURI);
                    foreach (XmlNode node in xmlNode)
                    {
                        XmlElement nodeEl = (XmlElement) node;

                        //创建二级子节点
                        XmlElement nodeB = xmlDoc.CreateElement(node.Name, xmlDoc.DocumentElement.NamespaceURI);
                        if (nodeEl.GetAttribute("Include") != null)
                        {
                            nodeB.SetAttribute("Include", nodeEl.GetAttribute("Include"));
                        }

                        //创建三级子节点
                        foreach (XmlNode n in node)
                        {
                            XmlElement nodeC = xmlDoc.CreateElement(n.Name, xmlDoc.DocumentElement.NamespaceURI);
                            nodeC.InnerText = n.InnerText;
                            nodeB.AppendChild(nodeC);
                        }

                        nodeA.AppendChild(nodeB);
                    }

                    creatList.Add(nodeA);
                }

                foreach (XmlNode xmlNode in creatList)
                {
                    rootNode.InsertAfter(xmlNode, flagNode);
                    flagNode = xmlNode;
                }

                reader.Close();
                xmlDoc.Save(XMLPath);
            }
            catch (Exception e)
            {
            }
        }

        /// <summary>
        /// 根据属性获得子节点的内容
        /// </summary>
        /// <param name="XMLPath"></param>
        /// <param name="XmlNodeName"></param>
        /// <param name="type"></param>
        /// <returns></returns>
        public static string GetXmlNodeOfAttribute(string XMLPath, string rootNodeName, string XmlNodeName, string version)
        {
            string str = null;

            XmlNode XmlNode = GetXmlNode(XMLPath, XmlNodeName);

            XmlNodeList nodeList = XmlNode.ChildNodes;

            foreach (XmlNode node in nodeList)
            {
                XmlElement xmlElement = (XmlElement) node;
                if (xmlElement.GetAttribute("Version").ToString() == version)
                {
                    str = xmlElement.InnerText;
                }
            }

            return str;
        }

        /// <summary>
        /// 修改addin文件
        /// </summary>
        /// <param name="addinPathDes"></param>
        /// <param name="dllPath"></param>
        /// <param name="addinPathSrc"></param>
        /// <returns></returns>
        public static void ChangeXml(string addinPath, string dllPath)
        {
            XElement xelement = XElement.Load(addinPath);
            foreach (XNode node in xelement.Nodes())
            {
                if (node.NodeType == XmlNodeType.Element)
                {
                    XElement sub = node as XElement;

                    if (sub != null)
                    {
                        foreach (XNode item in sub.Nodes())
                        {
                            XElement sub2 = item as XElement;
                            if (sub2.Name == "Assembly")
                            {
                                sub2.Value = dllPath;
                            }
                        }
                    }
                }
            }

            xelement.Save(addinPath);
        }

        #endregion

        #region 私有内部方法

        /// <summary>
        /// 检查XML是否存在
        /// </summary>
        /// <param name="XMLPath">XML的路径</param>
        /// <returns></returns>
        private static bool CheckXMLFile(string XMLPath)
        {
            if (!File.Exists(XMLPath))
            {
                return false;
            }

            try
            {
                XmlDocument xmlDoc = new XmlDocument();
                XmlReaderSettings settings = new XmlReaderSettings();
                settings.IgnoreComments = true; //忽略文档里面的注释
                XmlReader reader = XmlReader.Create(XMLPath, settings);
                xmlDoc.Load(reader);

                reader.Close();

                return true;
            }
            catch (Exception e)
            {
                Debug.Assert(false);
                return false;
            }
        }

        /// <summary>
        /// 向XML配置文件中添加的节点
        /// </summary>
        /// <param name="XMLPath"></param>
        private static void CreateXMLFile(string XMLPath)
        {
            XmlDocument xmlDoc = new XmlDocument();

            //创建类型声明节点  
            XmlNode node = xmlDoc.CreateXmlDeclaration("1.0", "utf-8", "");
            xmlDoc.AppendChild(node);

            //创建根节点  
            XmlNode root = xmlDoc.CreateElement(RootNode);
            xmlDoc.AppendChild(root);

            //创建维护项目名称的子节点
            XmlNode projectNameNode = xmlDoc.CreateNode(XmlNodeType.Element, ProjectNameNode, null);
            projectNameNode.InnerText = _projName;
            root.AppendChild(projectNameNode);

            //创建维护Revit版本的子节点
            XmlNode revitVersionNode = xmlDoc.CreateNode(XmlNodeType.Element, RevitVersionNode, null);
            CreateXMLNode(xmlDoc, revitVersionNode, VersionNode, _version1);
            CreateXMLNode(xmlDoc, revitVersionNode, VersionNode, _version2);
            root.AppendChild(revitVersionNode);

            //创建维护Debug路径的子节点
            XmlNode debugPathNode = xmlDoc.CreateNode(XmlNodeType.Element, DebugPathNode, null);
            CreateXMLNode(xmlDoc, debugPathNode, PathNode, _debug1, NodeAttribute, _version1);
            CreateXMLNode(xmlDoc, debugPathNode, PathNode, _debug2, NodeAttribute, _version2);
            root.AppendChild(debugPathNode);

            //创建维护Release路径的子节点
            XmlNode releasePathNode = xmlDoc.CreateNode(XmlNodeType.Element, ReleasePathNode, null);
            CreateXMLNode(xmlDoc, releasePathNode, PathNode, _release1, NodeAttribute, _version1);
            CreateXMLNode(xmlDoc, releasePathNode, PathNode, _release2, NodeAttribute, _version2);
            root.AppendChild(releasePathNode);

            //创建Csproj版本路径子节点
            XmlNode csprojPathNode = xmlDoc.CreateNode(XmlNodeType.Element, CsprojPathNode, null);
            CreateXMLNode(xmlDoc, csprojPathNode, PathNode, _csproj1, NodeAttribute, _version1);
            CreateXMLNode(xmlDoc, csprojPathNode, PathNode, _csproj2, NodeAttribute, _version2);
            root.AppendChild(csprojPathNode);

            try
            {
                xmlDoc.Save(XMLPath);
            }
            catch (Exception e)
            {
            }
        }

        /// <summary>
        /// 创建XML节点
        /// </summary>
        /// <param name="xmlDoc"></param>
        /// <param name="parentNode">父节点</param>
        /// <param name="name">节点名称</param>
        /// <param name="value">节点内容</param>
        private static XmlNode CreateXMLNode(XmlDocument xmlDoc, XmlNode parentNode, string name, string value)
        {
            XmlNode node = xmlDoc.CreateNode(XmlNodeType.Element, name, null);
            node.InnerText = value;
            parentNode.AppendChild(node);
            return node;
        }

        /// <summary>
        /// 创建XML节点，包含属性
        /// </summary>
        /// <param name="xmlDoc"></param>
        /// <param name="parentNode">父节点</param>
        /// <param name="name">节点名称</param>
        /// <param name="value">节点内容</param>
        /// <param name="attributeName">属性名称</param>
        /// <param name="attributeValue">属性内容</param>
        private static XmlNode CreateXMLNode(XmlDocument xmlDoc, XmlNode parentNode, string name, string value, string attributeName, string attributeValue)
        {
            XmlNode node = xmlDoc.CreateNode(XmlNodeType.Element, name, null);
            node.InnerText = value;
            XmlAttribute attr = xmlDoc.CreateAttribute(attributeName);
            attr.Value = attributeValue;
            node.Attributes.Append(attr);
            parentNode.AppendChild(node);
            return node;
        }

        #endregion
    }
}